package gatperdut.chato.core.entities;

import gatperdut.chato.constants.CSConstantsCommandResult.CommandExecutionResult;
import gatperdut.chato.constants.CSConstantsPlayerState.PlayerState;
import gatperdut.chato.constants.CSConstantsString;
import gatperdut.chato.core.ChatoServer;
import gatperdut.chato.core.characters.BaseController;
import gatperdut.chato.core.characters.health.HealthController;
import gatperdut.chato.core.interpreter.PlayerInterpreter;
import gatperdut.chato.core.item.inventory.EntityInventoryController;
import gatperdut.chato.core.scores.ScoresController;
import gatperdut.chato.core.skills.SkillsController;
import gatperdut.chato.model.Chato.Player.Player;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import org.apache.log4j.Logger;

public class PlayerController extends BaseController {

    private final Logger logger = Logger.getLogger( PlayerController.class );

    private final Socket socket;

    private BufferedReader input = null;

    private PrintWriter output = null;

    private PlayerState playerState;

    private Player player = null;

    public PlayerController( ChatoServer chatoServer, Socket socket ) {
        super( chatoServer );

        playerState = PlayerState.LOGIN_PROVIDING_USERNAME;

        this.socket = socket;
        if ( socket != null ) {
            try {
                input = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
                output = new PrintWriter( socket.getOutputStream(), true );
            }
            catch ( IOException e ) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void doRun() {

        tx( "Welcome to Chato MUD. Your username?" );

        CommandExecutionResult cer = CommandExecutionResult.OK;
        String command;
        while ( ( command = rx() ) != null ) {
            switch ( playerState.getEntityStateGroup() ) {
            case GROUP_LOGIN:
                cer = getInterpreter().getPlayerLogin().handleLogin( command );
                if ( cer == CommandExecutionResult.LOGIN_PASSWORD_MATCHING ) {
                    tx( getInterpreter().getPlayerMainMenu().getMainMenuString() );
                    setPlayerState( PlayerState.IN_MAIN_MENU );
                }
                break;
            case GROUP_MAIN_MENU:
                cer = getInterpreter().getPlayerMainMenu().handleMainMenu( command.trim() );
                if ( cer == CommandExecutionResult.MAIN_MENU_ENTER_GAME ) {
                    setPlayerState( PlayerState.IN_GAME );
                    setCharacter( player.getCurrentPC() );
                    loadSubControllers();
                    getRoomController().getCharactersController().enterRoom( this );
                    tx( getRoomController().show( this ) );
                    getEchoes().txEnterArea();
                    getLogger().info( getPlayer().getUsername() + " enters the game with " + getCharacter().getName() + " (" + getCharacter().getShortDesc() + ")" );
                    getChatoServer().getEntityHandler().addPlayerInGame();
                }
                break;
            case GROUP_IN_GAME:
                cer = getInterpreter().exec( command );
                break;
            }
            if ( cer.getQuit() ) {
                if ( cer == CommandExecutionResult.QUIT_TO_MAIN_MENU ) {
                    tx( getInterpreter().getPlayerMainMenu().getMainMenuString() );
                    setPlayerState( PlayerState.IN_MAIN_MENU );
                    getLogger().info( getPlayer().getUsername() + " leaves the game with " + getCharacter().getName() + " (" + getCharacter().getShortDesc() + ")" );
                }
                else {
                    break;
                }
            }
        }
        try {
            socket.close();
        }
        catch ( IOException e ) {
            e.printStackTrace();
        }

    }

    private void loadSubControllers() {
        // --inventory
        EntityInventoryController inventoryController = new EntityInventoryController( getChatoServer(), getCharacter().getInventory(), this );
        setInventoryController( inventoryController );
        // --scores
        ScoresController scoresController = new ScoresController( getCharacter().getScores() );
        setScoresController( scoresController );
        // --health
        HealthController healthController = new HealthController( getCharacter().getHealth() );
        setHealthController( healthController );
        // --skills
        SkillsController skillController = new SkillsController( getCharacter().getSkillsContainer() );
        setSkillsController( skillController );
        // --room controller
        setRoomController( getChatoServer().getRoomHandler().getRoomToController().get( getCharacter().getRoom() ) );
    }

    @Override
    public void tx( String message ) {
        switch ( getPlayerState().getEntityStateGroup() ) {
        case GROUP_IN_GAME:
            getOutput().println( message + CSConstantsString.NEWLINE + getQuickStatus() );
            break;
        case GROUP_LOGIN:
        case GROUP_MAIN_MENU:
            getOutput().println( message );
            break;
        default:
            throw new IllegalArgumentException( "Unknown player state when tx'ing." );

        }
    }

    public void logout() {
        getRoomController().getCharactersController().leaveRoom( this );
        getChatoServer().getEntityHandler().removePlayerInGame();
        getInventoryController().unloadItems();
    }

    @Override
    public void die( BaseController killer ) {
        super.die( killer );
        setPlayerState( PlayerState.IN_MAIN_MENU );
        tx( getInterpreter().getPlayerMainMenu().getMainMenuString() );
    }

    public void setOutput( PrintWriter output ) {
        this.output = output;
    }

    @Override
    public String rx() {
        try {
            return getInput().readLine();
        }
        catch ( IOException e ) {
            return null;
        }
    }

    public Socket getSocket() {
        return socket;
    }

    @Override
    public PlayerInterpreter getInterpreter() {
        return (PlayerInterpreter) super.getInterpreter();
    }

    public PlayerState getPlayerState() {
        return playerState;
    }

    public void setPlayerState( PlayerState playerState ) {
        this.playerState = playerState;
    }

    @Override
    public String whoAmI() {
        StringBuffer whoAmI = new StringBuffer( getSocket().getInetAddress() + ":" + getSocket().getPort() );
        if ( getPlayer() != null ) {
            whoAmI.append( " (" + getPlayer().getUsername() + ")" );
        }
        return whoAmI.toString();
    }

    public Player getPlayer() {
        return player;
    }

    public void setPlayer( Player player ) {
        this.player = player;
    }

    public PrintWriter getOutput() {
        return output;
    }

    public BufferedReader getInput() {
        return input;
    }

    public void setInput( BufferedReader input ) {
        this.input = input;
    }

    public Logger getLogger() {
        return logger;
    }
}
